package cn.jstars.datatocloud.main;

import cn.jstars.datatocloud.common.cache.Cache;
import cn.jstars.datatocloud.common.consts.Consts.CloudConst;
import cn.jstars.datatocloud.common.consts.Consts.CustomConst;
import cn.jstars.datatocloud.common.consts.Consts.RabbitMQ;
import cn.jstars.datatocloud.common.entity.Custom;
import cn.jstars.datatocloud.common.utils.DateUtil;
import cn.jstars.datatocloud.modules.base.MqService;
import cn.jstars.datatocloud.modules.dict.service.DictService;
import cn.jstars.datatocloud.modules.dict.task.ClientLogErrTask;
import cn.jstars.datatocloud.modules.dict.task.DictTask;
import cn.jstars.datatocloud.modules.heart.service.HeartService;
import cn.jstars.datatocloud.modules.heart.task.HeartTask;
import cn.jstars.datatocloud.modules.monitor.service.MonitorService;
import cn.jstars.datatocloud.modules.monitor.task.HistoryTask;
import cn.jstars.datatocloud.modules.monitor.task.MonitorTask;
import cn.jstars.datatocloud.modules.monitor.task.ParamSetTask;
import cn.jstars.datatocloud.modules.monitor.task.TMSTask;
import com.sun.tools.javac.util.Assert;
import org.nutz.lang.Strings;
import org.nutz.lang.Tasks;
import org.nutz.lang.util.NutMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


/**
 * 启动类
 *
 * @author Elvish
 */
@Component
public class Main {

    private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
    private static final String FLAG = "flag";
    private static final Integer RETRYCOUNT = 10;

    private Custom custom;
    private Cache cache;
    private MqService mqService;
    private HeartService heartService;
    private DictService dictService;
    private MonitorService monitorService;

    @Autowired
    public Main(Custom custom,Cache cache,MqService mqService,HeartService heartService,DictService dictService,MonitorService monitorService){
        Assert.checkNonNull(custom,"custom注入失败");
        Assert.checkNonNull(cache,"cache注入失败");
        Assert.checkNonNull(mqService,"mqService注入失败");
        Assert.checkNonNull(heartService,"heartService注入失败");
        Assert.checkNonNull(dictService,"dictService注入失败");
        Assert.checkNonNull(monitorService,"monitorService注入失败");
        this.custom = custom;
        this.cache = cache;
        this.mqService = mqService;
        this.heartService = heartService;
        this.dictService = dictService;
        this.monitorService = monitorService;
    }

    /**
     * 启动
     * <p>
     * 串行两件事
     * <p>
     * 1. 创建hasUpload字段
     * <p>
     * 2. 数据上云
     */
    public void start() {

        int year = DateUtil.getCurrentYear();

        List<String> allDays = DateUtil.getAllDaysByYear(year);

        if (CustomConst.ADD_COLUMN_IS_OK.equals(custom.getAddColumnFlag())) {
            try {
                addColumn(year, allDays);
            } catch (Exception e) {
                LOGGER.error("添加是否已经级联字段异常", e);
            }
        } else {

            // 初始化缓存
            cache.init();

            getCloudMQQueueName();

            if (Strings.isBlank(Cache.cloudMQQueueName)) {
                return;
            }

            startTask(year, allDays);

        }
    }

    /**
     * 添加字段
     *
     */
    private void addColumn(int year, List<String> allDays) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        if (Strings.isBlank(custom.getAddColumnStartTime())) {
            for (String day : allDays) {
                monitorService.addColumn(year, day);
                Thread.sleep(Long.parseLong(custom.getAddColumnIntervalTime()));
            }
        } else {
            for (String day : allDays) {
                if (sdf.parse(day).before(sdf.parse(custom.getAddColumnStartTime()))) {
                    continue;
                }
                monitorService.addColumn(year, day);
                Thread.sleep(Long.parseLong(custom.getAddColumnIntervalTime()));

            }
        }
    }

    /**
     * 请求服务器获取发送队列名称
     */
    private void getCloudMQQueueName() {
        try {

            int count = 0;

            String requestMsg = "{\"method\":\"needDataSync\",\"factoryId\":\"" + Cache.factoryId
                + "\",\"flag\":\"1\"}";
            String responseMsg = null;

            while ((Strings.isBlank(responseMsg) && count < RETRYCOUNT)) {
                try {
                    responseMsg = mqService.convertSendAndReceive(RabbitMQ.DATA_SYNC_SERVICE_DISCOVERY, requestMsg);
                } catch (Exception e) {
                    LOGGER.error("重试-请求服务器获取发送队列名称");
                    count++;
                }
            }

            if (Strings.isBlank(responseMsg)) {
                LOGGER.error("请求超时或服务不存在");
                return;
            }

            NutMap map = new NutMap(responseMsg);
            if (CloudConst.DATA_SYNC_IS_OK.equals(map.getString(FLAG))) {
                Cache.cloudMQQueueName = map.getString("queueName");
            } else {
                LOGGER.warn("服务器不允许该工厂进行数据级联，请联系管理员");
            }
        } catch (Exception e) {
            LOGGER.error("获取云端发送队列名称异常", e);
        }
    }

    /**
     * 启动任务
     *
     * @param year    年
     * @param allDays 天集合
     */
    private void startTask(int year, List<String> allDays) {

        ExecutorService executorService = Executors.newFixedThreadPool(16);
        startMonitorTask(executorService, year, allDays);

        startHeartTask();

        startDictTask();

        executorService.shutdown();
    }

    /**
     * 启动monitor级联任务
     *
     * @param executorService 线程池对象
     * @param year            年
     * @param allDays         天集合
     */
    private void startMonitorTask(ExecutorService executorService, int year, List<String> allDays) {

        // 数据上云
        // 1. 历史数据
        if (CustomConst.HISTORY_TASK_IS_OK.equals(custom.getHistoryTaskFlag())) {
            HistoryTask hTask = new HistoryTask(mqService, monitorService, year, allDays,
                Long.parseLong(custom.getHistoryTaskDayIntervalTime()));
            executorService.execute(hTask);
        }

        // 2. 实时数据
        MonitorTask mTask = new MonitorTask(mqService, monitorService, year,
            Long.parseLong(custom.getHistoryTaskDayIntervalTime()));

        // 5分钟一次
        Tasks.scheduleAtFixedRate(mTask, 0, 5, TimeUnit.MINUTES);

        // TMS除天表外其他数据
        TMSTask tTask = new TMSTask(mqService, monitorService, year);
        // 1小时一次
        Tasks.scheduleAtFixedRate(tTask, 0, 1, TimeUnit.HOURS);

        // 机台参数数据
        ParamSetTask psTask = new ParamSetTask(mqService, monitorService, year);
        // 10分钟一次
        Tasks.scheduleAtFixedRate(psTask, 0, 10, TimeUnit.MINUTES);
    }

    /**
     * 启动心跳级联任务
     */
    private void startHeartTask() {
        // 心跳数据级联任务
        HeartTask hTask = new HeartTask(mqService, heartService);
        // 10秒一次
        Tasks.scheduleAtFixedRate(hTask, 0, 10, TimeUnit.SECONDS);
    }

    /**
     * 启动字典级联任务
     */
    private void startDictTask() {
        DictTask dTask = new DictTask(mqService, dictService);
        // 1天一次
        Tasks.scheduleAtFixedRate(dTask, 0, 1, TimeUnit.DAYS);

        ClientLogErrTask logErrTask = new ClientLogErrTask(mqService, dictService);
        // 5分钟一次
        Tasks.scheduleAtFixedRate(logErrTask, 0, 5, TimeUnit.MINUTES);

    }

}
